package com.youme.tools.cg;

import java.util.Date;

import com.youme.tools.cg.consts.ConstDef;
import com.youme.tools.cg.consts.DateTimeFormat;
import com.youme.tools.cg.db.enums.DataSourceTypeEnum;
import com.youme.tools.cg.pojo.FieldBean;
import com.youme.tools.cg.pojo.TableBean;
import com.youme.tools.cg.util.DateTimeUtil;
import com.youme.tools.cg.util.NameFormatUtil;

public final class FileContentBuilder {
  FileContentBuilder() {}

  /**
   * 生成Java Entity Bean文件内容
   *
   * @param table 表数据
   * @param pkgName 包名
   * @return 字符串内容
   */
  public static String createJavaModelFileContent(TableBean table, String pkgName) {
    Date date = new Date();
    String clazzName = NameFormatUtil.formatClassName(table.getName());
    StringBuilder content = new StringBuilder();
    // package info
    content.append("package ").append(pkgName).append(";\n");
    content.append("import java.io.Serializable;\n\n");
    content.append("import io.swagger.annotations.ApiModel;\n");
    content.append("import io.swagger.annotations.ApiModelProperty;\n");
    content.append("import lombok.Data;\n");
    // class info
    content.append("/**\n");
    content.append("* ").append(table.getDescription()).append("\n");
    content.append("* @author Create By Code Generator\n");
    content.append("* @version ")
        .append(DateTimeUtil.formatDateTime(date, DateTimeFormat.YYYYMMDDHHMMSS)).append("\n");
    content.append("*/\n");
    content.append("@Data\n");
    content.append("@ApiModel(value = \"").append(clazzName).append("\", description = \"")
        .append(table.getDescription()).append("\")\n");
    content.append("public class ").append(clazzName).append(" implements Serializable {\n");
    content.append("    private static final long serialVersionUID = 1L;\n");
    // field info
    for (FieldBean field : table.getFields()) {
      String fieldName = field.getName();
      String fieldDesc = field.getDescription();
      String fieldDataType = field.getDataType();
      content.append("    /** ").append(fieldDesc).append(" */\n");
      content.append("    @ApiModelProperty(value = \"").append(fieldDesc)
          .append("\", dataType = \"").append(fieldDataType).append("\")\n");
      content.append("    private ").append(fieldDataType).append(" ")
          .append(NameFormatUtil.formatFieldName(fieldName)).append(";\n");

    }
    content.append("}\n");
    return content.toString();
  }

  /**
   * 生成DTO文件内容
   *
   * @param table 表数据
   * @param pkgName 包名
   * @return 字符串内容
   */
  public static String createDTOFileContent(TableBean table, String pkgName) {
    Date date = new Date();
    String clazzName = NameFormatUtil.formatClassName(table.getName());
    StringBuilder content = new StringBuilder();
    // package info
    content.append("package ").append(pkgName).append(";\n");
    content.append("import io.swagger.annotations.ApiModel;\n");
    content.append("import io.swagger.annotations.ApiModelProperty;\n");
    content.append("import lombok.Data;\n");
    // class info
    content.append("/**\n");
    content.append("* ").append(table.getDescription()).append("分页查询参数\n");
    content.append("* @author Create By Code Generator\n");
    content.append("* @version ")
        .append(DateTimeUtil.formatDateTime(date, DateTimeFormat.YYYYMMDDHHMMSS)).append("\n");
    content.append("*/\n");
    content.append("@Data\n");
    content.append("@ApiModel(value = \"").append(clazzName).append("PageParam\", description = \"")
        .append(table.getDescription()).append("分页查询参数\")\n");
    content.append("public class ").append(clazzName).append("PageParam extends BasePageParam {\n");
    content.append("    private static final long serialVersionUID = 1L;\n");
    content.append("    /** TODO:请根据实际需要修改查询条件中使用的参数 */\n");
    content.append("    @ApiModelProperty(value = \"\", dataType = \"String\")\n");
    content.append("    private String param;\n");
    content.append("}\n");
    return content.toString();
  }

  /**
   * 生成SQL MAP文件内容 ，包含最基本的CRUD方法
   * 
   * @param table 表数据
   * @param pkgName 包名
   * @return 字符串内容
   */
  public static String createSqlMapContent(TableBean table, String pkgName) {
    String clazzName = NameFormatUtil.formatClassName(table.getName());
    String daoName = pkgName + ConstDef.PACKAGE_SEPARATOR + clazzName + "DAO";
    StringBuilder content = new StringBuilder();
    // title begin
    content.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    content.append("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"")
        .append(" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n");
    content.append(String.format("<mapper namespace=\"%s\">\n", daoName));
    // title end

    // select sql begin
    content.append("    <sql id=\"allColumns\">\n");
    for (int i = 0; i < table.getFields().size(); i++) {
      FieldBean field = table.getFields().get(i);
      String fieldName = field.getName();
      if (i == table.getFields().size() - 1) {
        content.append("            ").append(fieldName).append(" AS ")
            .append(NameFormatUtil.formatFieldName(fieldName)).append("\n");
      } else {
        content.append("            ").append(fieldName).append(" AS ")
            .append(NameFormatUtil.formatFieldName(fieldName)).append(",\n");
      }
    }
    content.append("    </sql>\n");
    // select sql end

    // insert
    content.append(String.format("    <insert id=\"insert\" parameterType=\"%s\">\n", clazzName));
    DataSourceTypeEnum type = CodeGenerator.getDataBaseType();
    if (type == DataSourceTypeEnum.ORACLE) {
      content.append(
          "        <selectKey resultType=\"java.lang.Long\" order=\"BEFORE\" keyProperty=\"id\">\n");
      content.append("            SELECT ").append(table.getOriginalName())
          .append("_SEQUENCE.nextval AS id FROM dual\n");
      content.append("        </selectKey>\n");
    }

    content.append("        INSERT INTO ").append(table.getOriginalName()).append(" (\n");
    for (int i = 0; i < table.getFields().size(); i++) {
      FieldBean field = table.getFields().get(i);
      if (i == table.getFields().size() - 1) {
        content.append("            ").append(field.getName()).append("\n");
      } else {
        content.append("            ").append(field.getName()).append(",\n");
      }
    }
    content.append("        ) VALUES (\n");
    for (int i = 0; i < table.getFields().size(); i++) {
      FieldBean field = table.getFields().get(i);
      String fieldName = field.getName();
      if (i == table.getFields().size() - 1) {
        content.append("            #{").append(NameFormatUtil.formatFieldName(fieldName))
            .append(", jdbcType = VARCHAR}\n");
      } else {
        content.append("            #{").append(NameFormatUtil.formatFieldName(fieldName))
            .append(", jdbcType = VARCHAR},\n");
      }
    }
    content.append("        )\n");
    content.append("    </insert>\n");

    // modify
    content.append(String.format("    <update id=\"modify\" parameterType=\"%s\">\n", clazzName));
    content.append("        UPDATE ").append(table.getOriginalName()).append(" SET\n");
    for (int i = 0; i < table.getFields().size(); i++) {
      FieldBean field = table.getFields().get(i);
      String fieldName = field.getName();
      boolean isPK = field.getIsPK();
      if (!isPK) {
        if (i == table.getFields().size() - 1) {
          content.append("            ").append(fieldName).append(" = #{")
              .append(NameFormatUtil.formatFieldName(fieldName)).append(", jdbcType = VARCHAR}\n");
        } else {
          content.append("            ").append(fieldName).append(" = #{")
              .append(NameFormatUtil.formatFieldName(fieldName)).append(", jdbcType = VARCHAR},\n");
        }
      }
    }
    content.append("        WHERE 1 = 1\n");
    for (FieldBean field : table.getPks()) {
      String fieldName = field.getName();
      content.append("            AND ").append(fieldName).append(" = #{")
          .append(NameFormatUtil.formatFieldName(fieldName)).append(", jdbcType = VARCHAR}\n");
    }
    content.append("    </update>\n");

    // remove
    content.append(
        String.format("    <delete id=\"remove\" parameterType=\"%s\">\n", "java.lang.Long"));
    content.append("        DELETE FROM ").append(table.getOriginalName()).append("\n");
    content.append("        WHERE 1 = 1\n");
    for (FieldBean field : table.getPks()) {
      String fieldName = field.getName();
      content.append("            AND ").append(fieldName).append(" = #{")
          .append(NameFormatUtil.formatFieldName(fieldName)).append(", jdbcType = VARCHAR}\n");
    }
    content.append("    </delete>\n");

    // getById
    content.append(
        String.format("    <select id=\"getById\" parameterType=\"%s\" resultType=\"%s\">\n",
            "java.lang.Long", clazzName));
    content.append("        SELECT\n");
    content.append("        <include refid=\"allColumns\"></include>\n");
    content.append("        FROM ").append(table.getOriginalName()).append("\n")
        .append("        WHERE 1 = 1\n");
    for (FieldBean field : table.getPks()) {
      String fieldName = field.getName();
      content.append("            AND ").append(fieldName).append(" = #{")
          .append(NameFormatUtil.formatFieldName(fieldName)).append(", jdbcType = VARCHAR}\n");
    }
    content.append("    </select>\n");

    // list
    content
        .append(String.format("    <select id=\"list\" parameterType=\"%s\" resultType=\"%s\">\n",
            pkgName.replace(ConstDef.DAO_PACKAGE_NAME, ConstDef.DTO_PACKAGE_NAME) + "." + clazzName
                + "PageParam",
            clazzName));
    content.append("        SELECT\n");
    content.append("        <include refid=\"allColumns\"></include>\n");
    content.append("        FROM ").append(table.getOriginalName()).append("\n")
        .append("        WHERE 1 = 1\n");
    content.append("        ORDER BY id DESC\n");
    content.append("    </select>\n");

    content.append("</mapper>\n");
    return content.toString();
  }

  /**
   * 生成DAO接口文件
   *
   * @param table 表数据
   * @param pkgName 包名
   * @return 字符串内容
   */
  public static String createDAOFileContent(TableBean table, String pkgName, String moduleName) {
    Date date = new Date();
    String clazzName = NameFormatUtil.formatClassName(table.getName());
    StringBuilder content = new StringBuilder();

    // package info
    content.append("package ").append(moduleName).append(";\n");
    content.append("import java.util.List;\n\n");
    content.append("import org.apache.ibatis.annotations.Mapper;\n");
    content.append("import org.springframework.stereotype.Component;\n\n");
    // class info
    content.append("/**\n");
    content.append("* ").append(clazzName).append("数据访问层接口\n");
    content.append("* @ClassName: ").append(clazzName).append("DAO\n");
    content.append("* @author Create By Code Generator\n");
    content.append("* @version ")
        .append(DateTimeUtil.formatDateTime(date, DateTimeFormat.YYYYMMDDHHMMSS)).append("\n");
    content.append("*/\n");
    content.append("@Component\n");
    content.append("@Mapper\n");
    content.append("public interface ").append(clazzName).append("DAO {\n");
    content.append("    /**\n");
    content.append("     * 保存\n");
    content.append("     */\n");
    content.append("     int insert(").append(clazzName).append(" item);\n");
    content.append("    /**\n");
    content.append("     * 修改\n");
    content.append("     */\n");
    content.append("     int modify(").append(clazzName).append(" item);\n");
    content.append("    /**\n");
    content.append("     * 删除\n");
    content.append("     */\n");
    content.append("     int remove(Long id);\n");
    content.append("    /**\n");
    content.append("     * 根据Id获取\n");
    content.append("     */\n");
    content.append("     ").append(clazzName).append(" getById(Long id);\n");
    content.append("    /**\n");
    content.append("     * 按条件查询\n");
    content.append("     */\n");
    content.append("     List<").append(clazzName).append("> list(").append(clazzName)
        .append("PageParam param);\n");
    content.append("}\n");
    return content.toString();
  }

  /**
   * 生成Service接口文件
   * 
   * @Title: createServiceFileContent
   * @Description: 生成Service接口文件
   * @param table 表数据
   * @param pkgName 包名
   * @return 字符串内容
   */
  public static String createServiceFileContent(TableBean table, String pkgName,
      String moduleName) {
    Date date = new Date();
    String clazzName = NameFormatUtil.formatClassName(table.getName());
    StringBuilder content = new StringBuilder();

    // package info
    content.append("package ").append(moduleName).append(";\n");
    // class info
    content.append("/**\n");
    content.append("* ").append(clazzName).append("Service层接口\n");
    content.append("* @ClassName: ").append(clazzName).append("Service\n");
    content.append("* @author Create By Code Generator\n");
    content.append("* @version ")
        .append(DateTimeUtil.formatDateTime(date, DateTimeFormat.YYYYMMDDHHMMSS)).append("\n");
    content.append("*/\n");
    content.append("public interface ").append(clazzName).append("Service{\n");

    content.append("    /**\n");
    content.append("     * 根据Id获取\n");
    content.append("     */\n");
    content.append("     BaseResponse<").append(clazzName).append("> getById(Long id);\n");
    content.append("    /**\n");
    content.append("     * 分页查询\n");
    content.append("     */\n");
    content.append("     BaseResponse<BasePageResult<").append(clazzName).append(">> list(")
        .append(clazzName).append("PageParam param);\n");
    content.append("    /**\n");
    content.append("     * 保存\n");
    content.append("     */\n");
    content.append("     BaseResponse<String> insert(").append(clazzName).append(" item);\n");
    content.append("    /**\n");
    content.append("     * 修改\n");
    content.append("     */\n");
    content.append("     BaseResponse<String> modify(").append(clazzName).append(" item);\n");
    content.append("    /**\n");
    content.append("     * 删除\n");
    content.append("     */\n");
    content.append("     BaseResponse<String> remove(Long id);\n");
    content.append("}\n");
    return content.toString();
  }

  /**
   * 生成ServiceImpl文件
   * 
   * @Title: createServiceImplFileContent
   * @Description: 生成ServiceImpl文件
   * @param table 表数据
   * @param pkgName 包名
   * @return 字符串内容
   */
  public static String createServiceImplFileContent(TableBean table, String pkgName,
      String moduleName) {
    Date date = new Date();
    String clazzName = NameFormatUtil.formatClassName(table.getName());
    String camelClazzName = NameFormatUtil.formatFieldName(table.getName());
    StringBuilder content = new StringBuilder();

    // package info
    content.append("package ").append(moduleName).append(";\n\n");
    content.append("import java.util.List;\n\n");
    content.append("import org.springframework.beans.factory.annotation.Autowired;\n");
    content.append("import org.springframework.stereotype.Service;\n");
    content.append("import org.springframework.transaction.annotation.Transactional;\n\n");
    content.append("import com.github.pagehelper.Page;\n");
    content.append("import com.github.pagehelper.PageHelper;\n");
    content.append("import ")
        .append(moduleName.replace(ConstDef.SERVICE_IMPL_PACKAGE_NAME, ConstDef.DAO_PACKAGE_NAME))
        .append(".").append(clazzName).append("DAO;\n");
    content.append("import ")
        .append(
            moduleName.replace(ConstDef.SERVICE_IMPL_PACKAGE_NAME, ConstDef.SERVICE_PACKAGE_NAME))
        .append(".").append(clazzName).append("Service;\n\n");
    // class info
    content.append("/**\n");
    content.append("* ").append(clazzName).append("Service层实现类\n");
    content.append("* @ClassName: ").append(clazzName).append("ServiceImpl\n");
    content.append("* @author Create By Code Generator\n");
    content.append("* @version ")
        .append(DateTimeUtil.formatDateTime(date, DateTimeFormat.YYYYMMDDHHMMSS)).append("\n");
    content.append("*/\n");
    content.append("@Service\n");
    content.append("@SuppressWarnings(\"rawtypes\")\n");
    content.append("public class ").append(clazzName).append("ServiceImpl implements ")
        .append(clazzName).append("Service{\n");
    content.append("    @Autowired\n");
    content.append("    private ").append(clazzName).append("DAO ").append(camelClazzName)
        .append("DAO;\n\n");

    // getById
    content.append("    @Override\n");
    content.append("    public BaseResponse<").append(clazzName).append("> getById(Long id) {\n");
    content.append("        ").append(clazzName).append(" result = ").append(camelClazzName)
        .append("DAO.getById(id);\n");
    content.append("        return ResponseFactory.success(result, \"查询完成。\");\n");
    content.append("    }\n");

    // list
    content.append("    @Override\n");
    content.append("    public BaseResponse<BasePageResult<").append(clazzName).append(">> list(")
        .append(clazzName).append("PageParam param) {\n");
    content.append("        BasePageResult<").append(clazzName)
        .append("> result = new BasePageResult<>();\n");
    content.append("        int pageNum = param.getPageNum();\n");
    content.append("        int pageSize = param.getPageSize();\n");
    content.append("        PageHelper.startPage(pageNum, pageSize);\n");
    content.append("        List<").append(clazzName).append("> datas = ").append(camelClazzName)
        .append("DAO.list(param);\n");
    content.append("        int totalRecords = (int) ((Page) datas).getTotal();\n");
    content.append("        result.setDataList(datas);\n");
    content.append("        result.setTotalRecords(totalRecords);\n");
    content.append("        return ResponseFactory.success(result);\n");
    content.append("    }\n");

    // insert
    content.append("    @Override\n");
    content.append("    public BaseResponse<String> insert(").append(clazzName)
        .append(" item) {\n");
    content.append("        int affectedRows = ").append(camelClazzName)
        .append("DAO.insert(item);\n");
    content.append("        if (1 == affectedRows) {\n");
    content.append("            return ResponseFactory.success(\"数据处理成功！\");\n");
    content.append("        }\n");
    content.append("        return ResponseFactory.failure(\"数据处理失败！\");\n");
    content.append("    }\n");


    // modify
    content.append("    @Override\n");
    content.append("    public BaseResponse<String> modify(").append(clazzName)
        .append(" item) {\n");
    content.append("        int affectedRows = ").append(camelClazzName)
        .append("DAO.modify(item);\n");
    content.append("        if (1 == affectedRows) {\n");
    content.append("            return ResponseFactory.success(\"数据处理成功！\");\n");
    content.append("        }\n");
    content.append("        return ResponseFactory.failure(\"数据处理失败！\");\n");
    content.append("    }\n");

    // remove
    content.append("    @Override\n");
    content.append("    public BaseResponse<String> remove(Long id) {\n");
    content.append("        int affectedRows = ").append(camelClazzName)
        .append("DAO.remove(id);\n");
    content.append("        if (1 == affectedRows) {\n");
    content.append("            return ResponseFactory.success(\"数据处理成功！\");\n");
    content.append("        }\n");
    content.append("        return ResponseFactory.failure(\"数据处理失败！\");\n");
    content.append("    }\n");

    content.append("}\n");
    return content.toString();

  }

  /**
   * 生成Controller文件
   * 
   * @Title: createControllerFileContent
   * @Description: 生成Controller文件
   * @param table 表数据
   * @param pkgName 包名
   * @return 字符串内容
   */
  public static String createControllerFileContent(TableBean table, String pkgName,
      String moduleName) {
    Date date = new Date();
    String clazzName = NameFormatUtil.formatClassName(table.getName());
    String dtoName = moduleName.replace(ConstDef.DAO_PACKAGE_NAME, ConstDef.DTO_PACKAGE_NAME) + "."
        + clazzName + "PageParam";
    String camelClazzName = NameFormatUtil.formatFieldName(table.getName());
    StringBuilder content = new StringBuilder();

    // package info
    content.append("package ").append(moduleName).append(";\n\n");
    content.append("import javax.validation.Valid;\n\n");
    content.append("import org.springframework.beans.factory.annotation.Autowired;\n");
    content.append("import org.springframework.http.HttpStatus;\n");
    content.append("import org.springframework.http.ResponseEntity;\n");
    content.append("import org.springframework.validation.BindingResult;\n");
    content.append("import org.springframework.web.bind.annotation.GetMapping;\n");
    content.append("import org.springframework.web.bind.annotation.PathVariable;\n");
    content.append("import org.springframework.web.bind.annotation.PostMapping;\n");
    content.append("import org.springframework.web.bind.annotation.RequestBody;\n");
    content.append("import org.springframework.web.bind.annotation.RestController;\n\n");
    content.append("import ").append(pkgName).append(ConstDef.MODEL_PACKAGE_NAME).append(".")
        .append(clazzName).append(";\n");
    content.append("import ").append(dtoName).append(";\n");
    content.append("import ")
        .append(moduleName.replace(ConstDef.CONTROLLER_PACKAGE_NAME, ConstDef.SERVICE_PACKAGE_NAME))
        .append(".").append(clazzName).append("Service;\n\n");
    content.append("import io.swagger.annotations.Api;\n");
    content.append("import io.swagger.annotations.ApiOperation;\n");
    content.append("import lombok.extern.log4j.Log4j2;\n");
    // class info
    content.append("/**\n");
    content.append("* ").append(clazzName).append("RESTFUL APIs控制器\n");
    content.append("* @ClassName: ").append(clazzName).append("RestController\n");
    content.append("* @author Create By Code Generator\n");
    content.append("* @version ")
        .append(DateTimeUtil.formatDateTime(date, DateTimeFormat.YYYYMMDDHHMMSS)).append("\n");
    content.append("*/\n");
    content.append("@Log4j2\n");
    content.append("@SuppressWarnings(\"unchecked\")\n");
    content.append("@RestController\n");
    content.append("@Api(tags = \"").append(clazzName).append(" RESTFUL APIs\")\n");
    content.append("public class ").append(clazzName)
        .append("RestController extends BaseRestController{\n");
    content.append("    @Autowired\n");
    content.append("    private ").append(clazzName).append("Service ").append(camelClazzName)
        .append("Service;\n");

    // list
    content.append("    @ApiOperation(value = \"分页检索\")\n");
    content.append("    @PostMapping(value = \"/").append(camelClazzName).append("/list\")\n");
    content.append("    public ResponseEntity<BaseResponse<BasePageResult<").append(clazzName)
        .append(">>> list(@Valid @RequestBody BaseRequest<").append(clazzName)
        .append("PageParam> param, BindingResult validResult){\n");

    content.append("        if (validResult.hasErrors()) {\n");
    content.append("            return this.validateFailed(validResult);\n");
    content.append("        }\n");
    content.append("        BaseResponse<BasePageResult<").append(clazzName)
        .append(">> response = ").append(camelClazzName)
        .append("Service.list(param.getReqParam());\n");

    content.append(
        "        log.info(LOG_FORMAT, \"list\", JSONUtil.toJsonStr(param), JSONUtil.toJsonStr(response));\n");
    content.append("        return new ResponseEntity<>(response, HttpStatus.OK);\n");
    content.append("    }\n");

    // getById
    content.append("    @ApiOperation(value = \"根据ID获取\")\n");
    content.append("    @GetMapping(value = \"/").append(camelClazzName).append("/{id}\")\n");
    content.append("    public  ResponseEntity<BaseResponse<").append(clazzName)
        .append(">> getById(@PathVariable(\"id\") Long id){\n");

    content.append("        BaseResponse<").append(clazzName).append("> response =")
        .append(camelClazzName).append("Service.getById(id);\n");
    content.append(
        "        log.info(LOG_FORMAT, \"getById\", JSONUtil.toJsonStr(id), JSONUtil.toJsonStr(response));\n");
    content.append("        return new ResponseEntity<>(response, HttpStatus.OK);\n");
    content.append("    }\n");

    content.append("}\n");
    return content.toString();
  }

}
